﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;

namespace JsAndSilverLight.Web
{
    /// <summary>
    /// 将BingMap 的图片转换成 Arcgis 缓存地图的图片
    /// 将Bing Map 转换成 Arcgis Server 的瓦片地图缓存文件与生成对应的文件夹
    /// WGS 1984 WebMercator 
    /// </summary>
    public partial class px : System.Web.UI.Page
    {
        /// <summary>
        /// 地图源目录
        /// </summary>
        ///private string SourceMapDir = @"F:\Arcgis地图文件\上海(打开文件夹电脑会很慢很慢)\";
        private string SourceMapDir = "http://r3.tiles.ditu.live.com/tiles/";
        //默认空白图片
        private string EmptyMapFile = System.Web.HttpContext.Current.Server.MapPath("./empty.png");




        /// <summary>
        /// 採集用的東東
        /// </summary>
        public System.Net.WebClient wc = new System.Net.WebClient();

        protected void Page_Load(object sender, EventArgs e)
        {
            createCacheStruc(new List<double>(){
                120.339137303887, 30.5965286233398
                ,
                122.154095998457 ,31.8808961450195
            }
            , Range(1, 16),
            System.Web.HttpContext.Current.Server.MapPath("./tiles/")
            );

        }

        public List<int> Range(int start, int end)
        {
            List<int> tempList = new List<int>();
            if (start < end)
            {


                for (int i = start; i <= end; i++)
                {
                    tempList.Add(i);
                }
            }
            else
            {

                for (int i = end; i <= start; i++)
                {
                    tempList.Add(i);
                }
            }
            return tempList;
        }

        /// <summary>
        /// 创建某一等级下一行cache
        /// </summary>
        /// <param name="extent"></param>
        /// <param name="lv"></param>
        /// <param name="dir"></param>
        public void createLvCache(List<double> extent, int lv, string dir)
        {

            var startTile = getTileFromCdt(extent[0], extent[1], lv);
            var endTile = getTileFromCdt(extent[2], extent[3], lv);
            var xRange = Range(int.Parse(Math.Round(startTile.x).ToString("f0")), int.Parse(Math.Round(endTile.x).ToString("f0")));
            var yRange = Range(int.Parse(Math.Round(startTile.y).ToString("f0")), int.Parse(Math.Round(endTile.y).ToString("f0")));
            foreach (int row in yRange)
            {
                string rowName = dir + "/" + "R" + row.ToString("x8");

                //Response.Write(rowName + "<br/>");

                createCacheDir(rowName, lv, row, xRange);
            }
        }

        //创建缓存目录
        public void createCacheDir(string rowName, int lv, int row, List<int> xRange)
        {

            foreach (int col in xRange)
            {
                string localTile = rowName + "/" + "C" + col.ToString("x8") + ".png";
                string bingMapFile = SourceMapDir + "r" + TileXYToQuadKey(col, row, lv) + ".png" + "?g=77";

                #region 這裡進行採集

                //得到當前的buff
                byte[] imgBuff = null;

                try
                {
                    //正常寫入文件
                    imgBuff = wc.DownloadData(bingMapFile);

                    WriteDirOrFile(localTile, imgBuff);
                }
                catch
                {
                    WriteDirOrFile(localTile, System.IO.File.ReadAllBytes(EmptyMapFile));

                    //寫入出錯 採集失敗 的文件
                    System.IO.File.AppendAllText(Server.MapPath("./" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt"), bingMapFile + "\r\n");
                }


                #endregion



            }
        }


        /// <summary>
        /// 将缓存地图的 x,y level转换成 QuadKey
        /// </summary>
        /// <param name="tileX">将缓存地图的 X </param>
        /// <param name="tileY">将缓存地图的 Y </param>
        /// <param name="levelOfDetail">地图的当前放大的等级</param>
        /// <returns>返回 QuadKey.</returns>
        public static string TileXYToQuadKey(int tileX, int tileY, int levelOfDetail)
        {
            StringBuilder quadKey = new StringBuilder();
            for (int i = levelOfDetail; i > 0; i--)
            {
                char digit = '0';
                int mask = 1 << (i - 1);
                if ((tileX & mask) != 0)
                {
                    digit++;
                }
                if ((tileY & mask) != 0)
                {
                    digit++;
                    digit++;
                }
                quadKey.Append(digit);
            }
            return quadKey.ToString();
        }

        /// <summary>
        /// 根据经纬度坐标以及缩放等级获取像素坐标
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        public Cdt getPixelFromCdt(double x, double y, int z)
        {
            Cdt pixel = new Cdt();
            var sinLatitude = Math.Sin(y * Math.PI / 180);
            pixel.x = ((x + 180) / 360) * 256 * Math.Pow(2, z);
            double temp = Math.Log((1 + sinLatitude) / (1 - sinLatitude));
            pixel.y = Math.Abs((0.5 - temp / (4 * Math.PI)) * 256 * Math.Pow(2, z));
            return pixel;
        }

        /// <summary>
        /// 根据像素坐标获取切片
        /// </summary>
        /// <param name="pixel"></param>
        /// <returns></returns>
        public Cdt getTileFromPixel(Cdt pixel)
        {
            Cdt tile = new Cdt();
            tile.x = Math.Floor(pixel.x / 256.0);
            tile.y = Math.Floor(pixel.y / 256.0);
            return tile;
        }

        /// <summary>
        /// 根据经纬度坐标以及缩放等级获取切片
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        public Cdt getTileFromCdt(double x, double y, int z)
        {

            return getTileFromPixel(getPixelFromCdt(x, y, z));
        }

        /// <summary>
        /// 存储cache下载列表
        /// </summary>
        protected IEnumerable<string> tempTask = new List<string>();

        /// <summary>
        /// 创建缓存目录结构及计算tile"
        /// </summary>
        /// <param name="extent"></param>
        /// <param name="lvRange"></param>
        /// <param name="cacheDir"></param>
        protected void createCacheStruc(List<double> extent, List<int> lvRange, string cacheDir)
        {
            int count = 0;
            Response.Write("创建Cache目录及计算tile数目..." + "<br/>");
            foreach (int lv in lvRange)
            {
                string lvName = "L0" + count;//lvName：等级文件夹名        
                Response.Write(cacheDir + "/" + lvName);//创建lv等级的文件夹，例如:lv01,lv02...
                createLvCache(extent, lv, cacheDir + "" + lvName);//创建完等级文件夹后，添加该等级的行文件夹，例如:R000001a0
                count += 1;
            }
        }

        /// <summary>
        /// 写入文件 如果文件夹不存在将自动创建
        /// </summary>
        /// <param name="FileName">文件名</param>
        /// <param name="FileContent">文件内容</param>
        protected void WriteDirOrFile(string FileName, byte[] FileContent)
        {

            //创建目录
            if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(FileName)))
            {
                System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(FileName));
            }
            //写入文件
            System.IO.File.WriteAllBytes(FileName, FileContent);
        }


    }
    /// <summary>
    /// cdt 类
    /// </summary>
    public class Cdt
    {
        public double x { get; set; }
        public double y { get; set; }

    }

    /// <summary>
    /// 常量設置類
    /// </summary>
    public static class ConstSet
    {
        public static string State { get; set; }
    }
}